/// Config Pins////
// I2C_SCL_PU  -> TP4 Connect to TP30 -> PIO2_9
// I2C_SDA_PU  -> TP3 Connect to TP8  -> PIO0_7
// UP_STREAM   -> TP2 Connect to TP27 -> PIO2_6
// DOWN_STREAM -> TP1 Connect to TP17 -> PIO1_8
///


#include "LPC11xx.h"			/* LPC11xx Peripheral Registers */
#include "../Common/type.h"
#include "../HAL/i2c.h"
#include "../DaisyLink/DaisyLink.h"
#include "../GPIO/gpio.h"
#include "../TIMER/timer.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "DL40.h"

/*******************************************************************************
**   Main Function  main()
*******************************************************************************/

struct Reg_t Reg;

TPinConfig g_pins[PINCOUNT];
TPinCount  g_pinCounters[PINCOUNT];
UINT16 g_lastADCRead;

void ResetPinConfig(UINT8 pin);
void SetupInterruptPin(UINT8 pin, UINT8 value);
void SetupCapturePin(UINT8 pin, UINT8 value);
void ProcessCommand(UINT8 pin, UINT8 command, UINT8 offset);
void ResetCounter(UINT8 pin);

UINT8 SetupADCGetChannel(UINT8 pin);
void SetupADC(UINT8 pin);

void SetPWMPeriod(UINT8 pin, UINT32 period_ns);
void SetPWMPinDuty(UINT8 pin, UINT32 duty_ns);
void DisablePWMPin(UINT8 pin);

int main (void)
{
	long lastInterruptTime = 0;
	
  HAL_Init_SysTick100us();
  GPIOInit();
	TIMERInit();
	
  memset(&Reg, 0, REGS_SIZE);
  DL_Initialize((struct DL_Regs*)&Reg, MANUFACTURER_GHI, MODULE_TYPE, MODULE_VERSION);

  while(TRUE)
	{
		// Wait until we are ready to begin the state machine
		if(0 == DL_Process())
		{
			continue;
		}
		
		if (Reg.InterruptActive == 1)
		{		
			if ((GetTicks() - lastInterruptTime) > 10)
			{
				DL_Interrupt();			
				Reg.InterruptActive = 0;	
				lastInterruptTime = GetTicks();
			}
		}		
	}
}

void DL_Platform_WriteRegister(UINT8 reg, UINT32 offset, UINT8 value)
{
	if((reg+offset) < REGS_SIZE)
	{
		*( ((BYTE*)&Reg) + reg + offset) = value;
	}
	else if (reg >= REG_FIRSTPINCONF && reg <= REG_LASTPINCONF)
	{
		int pin = reg - REG_FIRSTPINCONF;
		int port = pin / 12;
		int bit = pin % 12;
		
		g_pins[pin].Config = value;
		g_pins[pin].InterruptFlag = 0;
		g_pins[pin].Flags = 0;
		
		ResetPinConfig(pin);
		
		// Configure resistor mode for the pin
		switch (value & CONFIGPIN_MODEMASK)
		{
			case CONFIGPIN_PULLNONE: GPIOSetResistorMode(port, bit, 0); break;
			case CONFIGPIN_PULLDOWN: GPIOSetResistorMode(port, bit, 1); break;
			case CONFIGPIN_PULLUP: GPIOSetResistorMode(port, bit, 2); break;
			case CONFIGPIN_REPEATER: GPIOSetResistorMode(port, bit, 3); break;
		}
		
		// Configure the pin type and direction
		switch(value & CONFIGPIN_TYPEMASK)
		{
			case CONFIGPIN_OUT:
			{
				DrvGPIO_Open(port, bit, E_IO_OUTPUT);
			}
			break;
			
			case CONFIGPIN_IN:
			{
				DrvGPIO_Open(port, bit, E_IO_INPUT);
			}
			break;
		
			case CONFIGPIN_INT:
			{				
				// Set flag indicating that interrupts 
				// will be raised to the mainboard
				g_pins[pin].InterruptFlag = 1;
				
				// Wait for the arguments to be written 
				// before setting-up the interrupt pin
			}
			break;

			case CONFIGPIN_COUNTER:
			{
				// Wait for the arguments to be written
				// before setting-up the pulse counter
			}
			break;
			
			case CONFIGPIN_CAPTURE:
			{
				// Wait for the arguments to be written
				// before setting-up the capture pin
			}
			break;
			
			case CONFIGPIN_ADC:
			{
				SetupADC(pin);
			}
			
			case CONFIGPIN_PWM:
			{
				// Wait for the arguments to be written
				// before setting up the PWM pin
			}
			break;
		}		
	}	
	else if (reg >= REG_FIRSTCOMMAND && reg <= REG_LASTCOMMAND)
	{
		int pin = reg - REG_FIRSTCOMMAND;		
		
		if (offset > 8)
		{
			return;		
		}
		switch (offset)
		{
			case 0 : g_pins[pin].Command = value; break;
			default:				
				g_pins[pin].Arguments[offset - 1] = value;				
			break;
		}
		
		ProcessCommand(pin, g_pins[pin].Command, offset);
	}
}

UINT8 DL_Platform_ReadRegister(UINT8 reg, UINT32 offset)
{
	UINT8 c = 0xFF;
	
	if((reg+offset) < REGS_SIZE)
	{
		c = *( ((BYTE*)&Reg) + reg + offset );
	}
	else if (reg >= REG_FIRSTPINCONF && reg <= REG_LASTPINCONF)
	{
		int pin = reg - REG_FIRSTPINCONF;
		c = g_pins[pin].Config;
	}
	else if (reg >= REG_FIRSTPINVALUE && reg <= REG_LASTPINVALUE)
	{
		int pin = reg - REG_FIRSTPINVALUE;
		int port = pin / 12;
		int bit = pin % 12;
		
		//Is ADC pin
		if ((g_pins[pin].Config & CONFIGPIN_ADC) == CONFIGPIN_ADC)
		{
			UINT8 channel = SetupADCGetChannel(pin);
			//This is strange
			if (channel >= ADC_CHANNEL_COUNT)
				return 0;
			
			//On offset 0 we make read
			if (offset == 0)
			{
				//Read register
				g_lastADCRead = (LPC_ADC->DR[channel] >> 6) & 0x3FF;
				c = (BYTE)(g_lastADCRead & 0xFF);
			}
			else if (offset == 1)
			{
				c = (BYTE)((g_lastADCRead >> 8) & 0xFF);
			}
			else
			{
				c = 0;
			}
		}
		else
		{		
			c = GPIOGetValue(port, bit) != 0;
		}
	}
	else if (reg >= REG_FIRSTPINCOUNT && reg <= REG_LASTPINCOUNT)	
	{
		int pin = reg - REG_FIRSTPINCOUNT;
		
		switch(offset)
		{
			case 0 : 
				g_pinCounters[pin].LastCount = g_pinCounters[pin].Count;
			
				if ((g_pins[pin].Config & CONFIGPIN_TYPEMASK) == CONFIGPIN_CAPTURE)
				{
					switch(pin)
					{
						case 2: 	// 0.2
							g_pinCounters[pin].LastCount &= 0xffffffffffff0000;
							g_pinCounters[pin].LastCount |= LPC_TMR16B0->TC;
							break;
						case 20: 	// 1.8
							g_pinCounters[pin].LastCount &= 0xffffffffffff0000;
							g_pinCounters[pin].LastCount |= LPC_TMR16B1->TC;
							break;
						case 17:	// 1.5
							g_pinCounters[pin].LastCount &= 0xffffffff00000000;
							g_pinCounters[pin].LastCount |= LPC_TMR32B0->TC;
							break;
						case 12:	// 1.0
							g_pinCounters[pin].LastCount &= 0xffffffff00000000;
							g_pinCounters[pin].LastCount |= LPC_TMR32B1->TC;
							break;
					}
				}
							
				// If this is a normal interrupt pin we reset the count for the nex
				// interrupt read
				if ((g_pins[pin].Config & CONFIGPIN_TYPEMASK) == CONFIGPIN_INT)					
				{					
					g_pinCounters[pin].Count = 0;
				}
				
				c = (BYTE)(g_pinCounters[pin].LastCount & 0xff);
				
				if ((g_pins[pin].Flags & FLAG_RESETONREAD) == FLAG_RESETONREAD)
				{
					ResetCounter(pin);
				}										
				
				break;
			case 1 : c = (BYTE)((g_pinCounters[pin].LastCount >> 8) & 0xff); break;
			case 2 : c = (BYTE)((g_pinCounters[pin].LastCount >> 16) & 0xff); break;
			case 3 : c = (BYTE)((g_pinCounters[pin].LastCount >> 24) & 0xff); break;
		  case 4 : c = (BYTE)((g_pinCounters[pin].LastCount >> 32) & 0xff); break;
			case 5 : c = (BYTE)((g_pinCounters[pin].LastCount >> 40) & 0xff); break;
			case 6 : c = (BYTE)((g_pinCounters[pin].LastCount >> 48) & 0xff); break;
			case 7 : c = (BYTE)((g_pinCounters[pin].LastCount >> 56) & 0xff); break;
		}
	}
		
	return c;
}

void ProcessCommand(UINT8 pin, UINT8 command, UINT8 offset)
{
	switch (g_pins[pin].Config & CONFIGPIN_TYPEMASK)
	{
		case CONFIGPIN_OUT:
			switch(command)
			{
				case CMD_OUTPUTPIN_SET:
					// Arguments[0] - Pin state
					if (offset == 1)
					{
						int port = pin / 12;
						int bit = pin % 12;			
						GPIOSetValue(port, bit, g_pins[pin].Arguments[0] != 0);
					}
				break;
			}
		break;
			
		case CONFIGPIN_INT:
			switch(command)
			{
				case CMD_COMMON_CONFIG:
					// Arguments[0] - Pin sensitivity
				  if (offset == 1)
					{
						SetupInterruptPin(pin, g_pins[pin].Arguments[0]);
					}
				break;					
			}
		break;
			
		case CONFIGPIN_COUNTER:
			switch(command)
			{
				case CMD_COMMON_CONFIG:					
					// Arguments[0] - Pin sensitivity
				  // Arguments[1] - ResetOnRead
				  if (offset == 2)
					{
						SetupInterruptPin(pin, g_pins[pin].Arguments[0]);
						if (g_pins[pin].Arguments[1]) 
							g_pins[pin].Flags |= FLAG_RESETONREAD;
						else
							g_pins[pin].Flags &= ~FLAG_RESETONREAD;
					}
				break;
					
				case CMD_COUNTER_RESET:					
					g_pinCounters[pin].Count = 0;
				  g_pinCounters[pin].LastCount = 0;
				break;				
			}
		break;
			
		case CONFIGPIN_CAPTURE:
			switch(command)
			{
				case CMD_COMMON_CONFIG:
					// Arguments[0] - Pin sensitivity
					// Arguments[1] - ResetOnRead
					if (offset == 2)
					{
						SetupCapturePin(pin, g_pins[pin].Arguments[0]);
						if (g_pins[pin].Arguments[1]) 
							g_pins[pin].Flags |= FLAG_RESETONREAD;
						else
							g_pins[pin].Flags &= ~FLAG_RESETONREAD;
					}
				break;
					
				case CMD_COUNTER_RESET:							
					ResetCounter(pin);				  
				break;							
			}
		break;
			
		case CONFIGPIN_PWM:
		{
			switch(command)
			{
				case CMD_PWMOUTPUTPIN_SETPULSE:
				{
					// Arguments[0..3]  - UINT32 Period in nanoseconds
					// Arguments[4..7]	- UINT32 Duty in nanoseconds
					if (offset == 8)
					{						
						UINT32 period_ns = g_pins[pin].Arguments[0] | (g_pins[pin].Arguments[1] << 8)
							| (g_pins[pin].Arguments[2] << 16) | (g_pins[pin].Arguments[3] << 24);
						
						UINT32 duty_ns = g_pins[pin].Arguments[4] | (g_pins[pin].Arguments[5] << 8)
							| (g_pins[pin].Arguments[6] << 16) | (g_pins[pin].Arguments[7] << 24);
						
						if (period_ns == 0 || duty_ns == 0)
						{
							DisablePWMPin(pin);
						}
						else
						{
							SetPWMPeriod(pin, period_ns);
							SetPWMPinDuty(pin, period_ns - duty_ns);
						}
					}
				}
				break;
				
				case CMD_PWMOUTPUTPIN_RESET:
				{
					DisablePWMPin(pin);
				}
				break;
			}
		}
		break;
	}
}

void SetupInterruptPin(UINT8 pin, UINT8 value)
{
	int port = pin / 12;
	int bit = pin % 12;
	
	g_pinCounters[pin].Count = 0;
	
	DrvGPIO_Open(port, bit, E_IO_INPUT);
	GPIOIntEnable(port, bit);
	switch(value)
	{
		case InterruptEdgeLow:
			GPIOSetInterrupt(port, bit, 0, 0, 0);
		break;
		
		case InterruptEdgeHigh:
			GPIOSetInterrupt(port, bit, 0, 0, 1);
		break;

		case InterruptEdgeBoth:
			GPIOSetInterrupt(port, bit, 0, 1, 0);
		break;
		
		case InterruptEdgeLevelHigh:
			GPIOSetInterrupt(port, bit, 1, 0, 1);
		break;

		case InterruptEdgeLevelLow:
			GPIOSetInterrupt(port, bit, 1, 0, 0);
		break;				
	}
}

void SetupCapturePin(UINT8 pin, UINT8 value)
{
	int port = pin / 12;
	int bit = pin % 12;
	
	// Enable Pin
	DrvGPIO_ClrBit(port, bit);
	DrvGPIO_Open(port, bit,  E_IO_INPUT);
	
	g_pinCounters[pin].Count = 0;
	
	if (port == 0 && bit == 2) // CT16B0
	{		
		if (value)
		{
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7); 	// Setup 16 bit timer 0 as counter
			LPC_IOCON->PIO0_2 &= ~0x07;					 		// Timer0_16 I/O config
			LPC_IOCON->PIO0_2 |= 0x02;					 		// Timer0_16 CAP0		
			LPC_TMR16B0->CCR = value;            		// 1 - Rising edge, 2 - Falling edge
			LPC_TMR16B0->CTCR = (0x1 << 1);      		// Use pin as clock
			LPC_TMR16B0->TCR = 1;				
			LPC_TMR16B0->TC = 0;
			LPC_TMR16B0->MR0 = 0x0;									// Interrupt when match 0 to detect overflow
			LPC_TMR16B0->MCR |= 0x01;								// Interrupt if match channel 0
			
			g_timer16_0_type = CONFIGPIN_CAPTURE;
		}
		else
		{
			g_timer16_0_type = 0;
			LPC_TMR16B0->MCR &= ~(0x01);
			LPC_TMR16B0->TCR = 0;
			LPC_TMR16B0->CTCR = 0;
			LPC_TMR16B0->CCR = 0;
			LPC_IOCON->PIO0_2 = 0;			
			LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 7);
		}
	}
	else if (port == 1 && bit == 8) // CT16B1
	{		
		if (value)
		{
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); 	// Setup 16 bit timer 1 as counter
			LPC_IOCON->PIO1_8 &= ~0x07;					   	// Timer1_16 I/O config
			LPC_IOCON->PIO1_8 |= 0x01;					 		// Timer1_16 CAP0		
			LPC_TMR16B1->CCR = value;            		// 1 - Rising edge, 2 - Falling edge
			LPC_TMR16B1->CTCR = (0x1 << 1);      		// Use pin as clock
			LPC_TMR16B1->TCR = 1;						
			LPC_TMR16B1->TC = 0;
			LPC_TMR16B1->MR0 = 0;										// Interrupt when match 0 to detect overflow			
			LPC_TMR16B1->MCR |= 0x01;								// Interrupt if match channel 0
			
			g_timer16_1_type = CONFIGPIN_CAPTURE;
		}
		else
		{
			g_timer16_1_type = 0;
			LPC_TMR16B1->MCR &= ~(0x01);
			LPC_TMR16B1->TCR = 0;
			LPC_TMR16B1->CTCR = 0;
			LPC_TMR16B1->CCR = 0;
			LPC_IOCON->PIO1_8 = 0;			
			LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 8);
		}
	}
	else if (port == 1 && bit == 5) // CT32B0
	{		
		if (value)
		{
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9); 	// Setup 32 bit timer 0 counter	
			LPC_IOCON->PIO1_5 &= ~0x07;					 		// Timer0_32 I/O config
			LPC_IOCON->PIO1_5 |= 0x02;					 		// Timer0_32 CAP0		
			LPC_TMR32B0->CCR = value;            		// 1 - Rising edge, 2 - Falling edge
			LPC_TMR32B0->CTCR = (0x1 << 1);      		// Use pin as clock
			LPC_TMR32B0->TCR = 1;			
			LPC_TMR32B0->TC = 0;			
			LPC_TMR32B0->MR0 = 0;										// Interrupt when match 0 to detect overflow
			LPC_TMR32B0->MCR |= 0x01;								// Interrupt if match channel 0
			
			g_timer32_0_type = CONFIGPIN_CAPTURE;			
		}
		else
		{
			g_timer32_0_type = 0;
			LPC_TMR32B0->MCR &= ~(0x01);
			LPC_TMR32B0->TCR = 0;
			LPC_TMR32B0->CTCR = 0;
			LPC_TMR32B0->CCR = 0;
			LPC_IOCON->PIO1_5 = 0;			
			LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 9);
		}
	}
	else if (port == 1 && bit == 0) // CT32B1
	{
		if (value)
		{
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10);	// Setup 32 bit timer 1 counter	
			LPC_IOCON->R_PIO1_0 &= ~0x07;				 		// Timer1_32 I/O config
			LPC_IOCON->R_PIO1_0 |= 0x03;				 		// Timer1_32 CAP0		
			LPC_TMR32B1->CCR = value;            		// 1 - Rising edge, 2 - Falling edge
			LPC_TMR32B1->CTCR = (0x1 << 1);      		// Use pin as clock
			LPC_TMR32B1->TCR = 1;						
			LPC_TMR32B1->TC = 0;			
			LPC_TMR32B1->MR0 = 0;										// Interrupt when match 0 to detect overflow
			LPC_TMR32B1->MCR |= 0x01;								// Interrupt if match channel 0
			
			g_timer32_1_type = CONFIGPIN_CAPTURE;
		}
		else
		{
			g_timer32_1_type = 0;
			LPC_TMR32B1->MCR &= ~(0x01);
			LPC_TMR32B1->TCR = 0;
			LPC_TMR32B1->CTCR = 0;
			LPC_TMR32B1->CCR = 0;
			LPC_IOCON->R_PIO1_0 = 0;			
			LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 10);
		}
	}	
}

void SetPWMPeriod(UINT8 pin, UINT32 period_ns)
{
	// Calculate match value for period
	UINT32 match = (UINT32)(((double)SystemFrequency / NanoSecond) * period_ns);
	
	switch (pin)
	{
		case PWM_CT16B0_MAT0_PIN:
		case PWM_CT16B0_MAT1_PIN:
		case PWM_CT16B0_MAT2_PIN:	
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7); 				// Setup 16 bit timer 0 counter	
			LPC_TMR16B0->MCR |= 0x01 << 10;								// Reset on MR3		
			LPC_TMR16B0->MR3 = (UINT16)match;							// Setup MR3 match value		
			LPC_TMR16B0->TCR = 1;													// Start the timer
			g_timer16_0_type = CONFIGPIN_PWM;		
			break;
		
		case PWM_CT16B1_MAT1_PIN:
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); 				// Setup 16 bit timer 1 counter	
			LPC_TMR16B1->MCR |= 0x01 << 10;								// Reset on MR3		
			LPC_TMR16B1->MR3 = (UINT16)match;							// Setup MR3 match value		
			LPC_TMR16B1->TCR = 1;													// Start the timer
			g_timer16_1_type = CONFIGPIN_PWM;
			break;
		
		case PWM_CT32B1_MAT0_PIN:
		case PWM_CT32B1_MAT2_PIN:	
			LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10);				// Setup 32 bit timer 1 counter	
			LPC_TMR32B1->MCR |= 0x01 << 10;								// Reset on MR3		
			LPC_TMR32B1->MR3 = match;											// Setup MR3 match value		
			LPC_TMR32B1->TCR = 1;													// Start the timer
			g_timer32_1_type = CONFIGPIN_PWM;
			break;
	}
}

void SetPWMPinDuty(UINT8 pin, UINT32 duty_ns)
{
	int port = pin / 12;
	int bit = pin % 12;
	
	// Calculate match value for duty
	UINT32 match = (UINT32)(((double)SystemFrequency / NanoSecond) * duty_ns);
	
	// Enable Pin
	DrvGPIO_ClrBit(port, bit);
	DrvGPIO_Open(port, bit,  E_IO_OUTPUT);
	
	switch(pin)
	{
		case PWM_CT16B0_MAT0_PIN:
			LPC_IOCON->PIO0_8 &= ~0x07;					 					// Timer0_16 I/O config
			LPC_IOCON->PIO0_8 |= 0x02;					 					//   - MAT0		
			LPC_TMR16B0->PWMC |= (1 << 0);								// Enable PWM on CT16B0_MAT0
			LPC_TMR16B0->EMR |= (2 << 4);									// Toggle output on MAT0 PIN 
			LPC_TMR16B0->MR0 = match;											// Set the duty cycle			
		break;
		
		case PWM_CT16B0_MAT1_PIN:
			LPC_IOCON->PIO0_9 &= ~0x07;					 					// Timer0_16 I/O config
			LPC_IOCON->PIO0_9 |= 0x02;					 					//   - MAT1		
			LPC_TMR16B0->PWMC |= (1 << 1);								// Enable PWM on CT16B0_MAT1
			LPC_TMR16B0->EMR |= (2 << 6);									// Toggle output on MAT1 PIN 
			LPC_TMR16B0->MR1 = match;											// Set the duty cycle			
		break;
		
		case PWM_CT16B0_MAT2_PIN:
			LPC_IOCON->SWCLK_PIO0_10 &= ~0x07;		 				// Timer0_16 I/O config
			LPC_IOCON->SWCLK_PIO0_10 |= 0x03;		 					//   - MAT2		
			LPC_TMR16B0->PWMC |= (1 << 2);								// Enable PWM on CT16B0_MAT2
			LPC_TMR16B0->EMR |= (2 << 8);									// Toggle output on MAT2 PIN 
			LPC_TMR16B0->MR2 = match;											// Set the duty cycle			
		break;
		
		case PWM_CT16B1_MAT1_PIN:
			LPC_IOCON->PIO1_10 &= ~0x07;									// Timer1_16 I/O config
			LPC_IOCON->PIO1_10 |= 0x02;										//   - MAT1		
			LPC_TMR16B1->PWMC |= (1 << 1);								// Enable PWM on CT16B0_MAT2
			LPC_TMR16B1->EMR |= (2 << 6);									// Toggle output on MAT2 PIN 
			LPC_TMR16B1->MR0 = match;											// Set the duty cycle			
		break;
		
		case PWM_CT32B1_MAT0_PIN:
			LPC_IOCON->R_PIO1_1 &= ~0x07;				 					// Timer1_32 I/O config
			LPC_IOCON->R_PIO1_1 |= 0x03;				 					//   - MAT0		
			LPC_TMR32B1->PWMC |= (1 << 0);								// Enable PWM on CT32B1_MAT0
			LPC_TMR32B1->EMR |= (2 << 4);									// Toggle output on MAT0 PIN 
			LPC_TMR32B1->MR0 = match;											// Set the duty cycle			
		break;
		
		case PWM_CT32B1_MAT2_PIN:
			LPC_IOCON->SWDIO_PIO1_3 &= ~0x07;			 				// Timer1_32 I/O config
			LPC_IOCON->SWDIO_PIO1_3 |= 0x03;							//   - MAT2		
			LPC_TMR32B1->PWMC |= (1 << 2);								// Enable PWM on CT32B1_MAT2
			LPC_TMR32B1->EMR |= (2 << 8);									// Toggle output on MAT2 PIN 
			LPC_TMR32B1->MR2 = match;											// Set the duty cycle			
		break;
	}
}

void DisablePWMPin(UINT8 pin)
{
	switch(pin)
	{
		case PWM_CT16B0_MAT0_PIN:
			LPC_IOCON->PIO0_8 &= ~0x07;					 					// Timer0_16 I/O config			
			LPC_TMR16B0->PWMC &= ~(1 << 0);								// Disable PWM on CT16B0_MAT0
			LPC_TMR16B0->EMR &= ~(2 << 4);								// Toggle output on MAT0 PIN 
			LPC_TMR16B0->MR0 = 0;													// Set the duty cycle			
		break;
		
		case PWM_CT16B0_MAT1_PIN:
			LPC_IOCON->PIO0_9 &= ~0x07;					 					// Timer0_16 I/O config			
			LPC_TMR16B0->PWMC &= ~(1 << 1);								// Disable PWM on CT16B0_MAT1
			LPC_TMR16B0->EMR &= ~(2 << 6);								// Toggle output on MAT1 PIN 
			LPC_TMR16B0->MR1 = 0;													// Set the duty cycle			
		break;
		
		case PWM_CT16B0_MAT2_PIN:
			LPC_IOCON->SWCLK_PIO0_10 &= ~0x07;		 				// Timer0_16 I/O config			
			LPC_TMR16B0->PWMC &= ~(1 << 2);								// Disable PWM on CT16B0_MAT2
			LPC_TMR16B0->EMR &= ~(2 << 8);								// Toggle output on MAT2 PIN 
			LPC_TMR16B0->MR2 = 0;													// Set the duty cycle			
		break;
		
		case PWM_CT16B1_MAT1_PIN:
			LPC_IOCON->PIO1_10 &= ~0x07;									// Timer1_16 I/O config
			LPC_TMR16B1->PWMC &= ~(1 << 1);								// Disable PWM on CT16B0_MAT2
			LPC_TMR16B1->EMR &= ~(2 << 6);								// Toggle output on MAT2 PIN 
			LPC_TMR16B1->MR0 = 0;													// Set the duty cycle			
		break;
		
		case PWM_CT32B1_MAT0_PIN:
			LPC_IOCON->R_PIO1_1 &= ~0x07;				 					// Timer1_32 I/O config
			LPC_TMR32B1->PWMC &= ~(1 << 0);								// Disable PWM on CT32B1_MAT0
			LPC_TMR32B1->EMR &= ~(2 << 4);								// Toggle output on MAT0 PIN 
			LPC_TMR32B1->MR0 = 0;													// Set the duty cycle			
		break;
		
		case PWM_CT32B1_MAT2_PIN:
			LPC_IOCON->SWDIO_PIO1_3 &= ~0x07;			 				// Timer1_32 I/O config
			LPC_TMR32B1->PWMC &= ~(1 << 2);								// Disable PWM on CT32B1_MAT2
			LPC_TMR32B1->EMR &= ~(2 << 8);								// Toggle output on MAT2 PIN 
			LPC_TMR32B1->MR2 = 0;													// Set the duty cycle			
		break;
	}
}

UINT8 SetupADCGetChannel(UINT8 pin)
{
	switch (pin)
	{
		case 11:
			return 0;
		case 12:
			return 1;
		case 13:
			return 2;
		case 14:
			return 3;
		case 16:
			return 5;
		case 22:
			return 6;
		case 23:
			return 7;
		default:
			return 0xFF;
	}
}

void SetupADC(UINT8 pin)
{
	UINT8 channel = SetupADCGetChannel(pin);
	if (channel >= ADC_CHANNEL_COUNT)
		return;
	
	//Enable ADC, could be first time only
	LPC_SYSCON->PDRUNCFG &= ~(1 <<4);
	LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);
	//Enable BURST mode and CLKDIV
	LPC_ADC->CR |= (1<<16) | (0xF << 8);
	
	//AD5-AD7 have different FUNC value on the pin for ADC
	if (channel < 5)
	{
		//Select ADMODE on PIN and set FUNC (0 to bit 7 and 010 on bi 2:0)
		*IOCON_PIO[pin] = ((*IOCON_PIO[pin] & (0x7)) | 0x2) & (~(1 << 7));
	}
	else
	{
		*IOCON_PIO[pin] = ((*IOCON_PIO[pin] & (0x7)) | 0x1) & (~(1 << 7));
	}

	//Enable reading from selected pin
	LPC_ADC->CR |= (1<<channel);
}

void DisableADC(UINT8 pin)
{
	UINT8 channel = SetupADCGetChannel(pin);
	//Not ADC pin
	if (channel >= ADC_CHANNEL_COUNT)
		return;	
	
	//Set FUNC (2:0) to 0 and 7 to 1
	*IOCON_PIO[pin] &= ~(0x7);
	*IOCON_PIO[pin] |= (1 << 7);	
}

void ResetPinConfig(UINT8 pin)
{
	int port = pin / 12;
	int bit = pin % 12;
	
	DisableADC(pin);
	DisablePWMPin(pin);
	
	switch (pin)
	{
		// Reset capture pins
		case TIMER_B16_0_PIN:
		case TIMER_B16_1_PIN:
		case TIMER_B32_0_PIN:
		case TIMER_B32_1_PIN:				
			SetupCapturePin(pin, 0);
			break;
	}
	
	GPIOIntDisable(port, bit);
	GPIOSetInterrupt(port, bit, 0, 0, 0);	
	GPIOSetDir(port, bit, E_IO_OUTPUT);
}

void ResetCounter(UINT8 pin)
{
	switch (pin)
	{
		case TIMER_B16_0_PIN: LPC_TMR16B0->MCR &= ~(0x01); LPC_TMR16B0->TC = 0; LPC_TMR16B0->MCR = 0x01; break;
		case TIMER_B16_1_PIN: LPC_TMR16B1->MCR &= ~(0x01); LPC_TMR16B1->TC = 0; LPC_TMR16B1->MCR = 0x01; break;
		case TIMER_B32_0_PIN: LPC_TMR32B0->MCR &= ~(0x01); LPC_TMR32B0->TC = 0; LPC_TMR32B0->MCR = 0x01; break;
		case TIMER_B32_1_PIN: LPC_TMR32B1->MCR &= ~(0x01); LPC_TMR32B1->TC = 0; LPC_TMR32B1->MCR = 0x01; break;
	}					
	g_pinCounters[pin].Count = 0;
}

void HAL_SharedPinLow(int pin)
{
	switch(pin)
	{
		case UPSTREAM_PIN:
			DrvGPIO_ClrBit(US_PORT, US_PIN);
			DrvGPIO_Open(US_PORT, US_PIN,  E_IO_OUTPUT);
			if (GPIOGetValue(US_PORT, US_PIN) != 0)
			{
				DrvGPIO_ClrBit(US_PORT, US_PIN);
			}
			break;
	}	
}

void HAL_SharedPinInput(int pin)
{
   switch(pin)
	{
		case UPSTREAM_PIN:
			DrvGPIO_Open(US_PORT, US_PIN,  E_IO_INPUT);
			
			break;
	}
}

UINT8 HAL_SharedPinRead(int pin)
{

 switch(pin)
	{
		case UPSTREAM_PIN:
			return (((DrvGPIO_GetBit(US_PORT, US_PIN)) != 0)?1:0);
		
			//break;
	}	
	return 0;
}  


void HAL_I2C_SetPullups(BOOL isOn)
{
	if(isOn)
	{
		DrvGPIO_SetBit(I2C_SCL_PU_PORT, I2C_SCL_PU_PIN);
		DrvGPIO_Open(I2C_SCL_PU_PORT, I2C_SCL_PU_PIN,  E_IO_OUTPUT);
		
		DrvGPIO_SetBit(I2C_SDA_PU_PORT, I2C_SDA_PU_PIN);
		DrvGPIO_Open(I2C_SDA_PU_PORT, I2C_SDA_PU_PIN,  E_IO_OUTPUT);
	}
	else
	{
		DrvGPIO_Open(I2C_SCL_PU_PORT, I2C_SCL_PU_PIN,  E_IO_INPUT);
		DrvGPIO_Open(I2C_SDA_PU_PORT, I2C_SDA_PU_PIN,  E_IO_INPUT);
      
	}
}

/******************************************************************************
**                            End Of File
******************************************************************************/
